/*
*    Phantom v2.0 GUI Automation Software
*    Copyright (C) 2009  John C. Van Arsdall (john@phantomtest.com)
*
*    This program is free software; you can redistribute it and/or modify
*    it under the terms of the GNU General Public License as published by
*    the Free Software Foundation; either version 2 of the License, or
*    (at your option) any later version.
*
*    This program is distributed in the hope that it will be useful,
*    but WITHOUT ANY WARRANTY; without even the implied warranty of
*    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*    GNU General Public License for more details.
*
*    You should have received a copy of the GNU General Public License along
*    with this program; if not, write to the Free Software Foundation, Inc.,
*    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
*/
#include "StdAfx.h"
#include ".\phantomjvm.h"
#include "JMinion_InternalErrors.h"

#include <direct.h>
#include "jni.h"

typedef struct{
	SSI_FunctionAPI *theAPI;
	String* ExtraData;
}JavaAPI;

typedef struct{
	String Tag;
	String Class;
	jobject obj;
}JavaWin;

// OK, so its a global...
String AppDir;

/////////////////////////////////////////////////////////////////////////////////////
CPhantomJVM::CPhantomJVM(void)
{
}

/////////////////////////////////////////////////////////////////////////////////////
CPhantomJVM::~CPhantomJVM(void)
{
}

/////////////////////////////////////////////////////////////////////////////////////
JavaVM* GetVM(){
	JavaVM*	javaVM = NULL;
	jsize size  = 0;
	JNI_GetCreatedJavaVMs(&javaVM, 1, &size);

	if(size == 0){		
		return 0;
	}

	return javaVM;
}

/////////////////////////////////////////////////////////////////////////////////////
JNIEnv*	GetEnv(JavaVM* VM){
	JNIEnv*	env = 0;
	jint res = 0;
	// Return value may mean nothing
	res = VM->AttachCurrentThread((void**)&env, NULL);	
	if(env == 0){
		return 0;
	}

	if(env->ExceptionOccurred()){
		env->ExceptionClear();
		return 0;
	}

	if(res < 0){
		return 0;
	}
	return env;
}

/////////////////////////////////////////////////////////////////////////////////////
SSI_INT64 GetNumeric(JNIEnv* env, jclass cls, jobject obj, jobjectArray arr, jsize len){
	SSI_INT64 ctr = 1;
	for(jsize ind = 0; ind < len; ind++){
		jobject frame = env->GetObjectArrayElement((jobjectArray)arr, ind);
		if(env->IsSameObject(frame, obj)){
			return ctr;
		}
		jclass other = env->GetObjectClass(frame);
		if(env->IsSameObject(other, cls)){
			ctr++;
		}
	}
	return ctr;
}

/////////////////////////////////////////////////////////////////////////////////////
String GetString(JNIEnv* env, jstring js){
	String Ret;
	if(js == 0){
		return Ret;
	}
	const char *str = env->GetStringUTFChars(js, 0);
	Ret = str;
	env->ReleaseStringUTFChars(js, str);
	return Ret;
}

/////////////////////////////////////////////////////////////////////////////////////
String toString(JNIEnv* env, jobject obj){
	jclass class_cls = env->FindClass("java/lang/Class");
	jmethodID toString = env->GetMethodID(class_cls, "toString", "()Ljava/lang/String;");

	String Ret;
	jstring js = (jstring)env->CallObjectMethod(obj, toString);
	return GetString(env, js);
}

/////////////////////////////////////////////////////////////////////////////////////
jmethodID getTitleID(JNIEnv* env, jclass cls){
	jmethodID getTitle = env->GetMethodID(cls, "getTitle", "()Ljava/lang/String;");
	if(env->ExceptionOccurred()){
		env->ExceptionClear();
		getTitle = env->GetMethodID(cls, "getText", "()Ljava/lang/String;");
		if(env->ExceptionOccurred()){
			env->ExceptionClear();
			getTitle = env->GetMethodID(cls, "getLabel", "()Ljava/lang/String;");
			if(env->ExceptionOccurred()){
				env->ExceptionClear();
				return 0;
			}
		}
	}
	return getTitle;
}

/////////////////////////////////////////////////////////////////////////////////////
jmethodID setTitleID(JNIEnv* env, jclass cls){
	jmethodID setTitle = env->GetMethodID(cls, "setTitle", "(Ljava/lang/String;)V");
	if(env->ExceptionOccurred()){
		env->ExceptionClear();
		setTitle = env->GetMethodID(cls, "setText", "(Ljava/lang/String;)V");
		if(env->ExceptionOccurred()){
			env->ExceptionClear();
			setTitle = env->GetMethodID(cls, "setLabel", "(Ljava/lang/String;)V");
			if(env->ExceptionOccurred()){
				env->ExceptionClear();
				return 0;
			}
		}
	}
	return setTitle;
}

/////////////////////////////////////////////////////////////////////////////////////
jobject CreateObject(JNIEnv* env, jclass cls){
	jmethodID create = env->GetMethodID(cls, "<init>", "()V");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return 0;
	}

	jobject obj = env->NewObject(cls, create);
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return 0;
	}

	return obj;
}

/////////////////////////////////////////////////////////////////////////////////////
jclass LoadClass(JNIEnv* env, const char* Path, const char* Name){
	FILE* FH = fopen(Path, "rb");
	if(!FH){
		return 0;
	}
	long start;
	long end;
	start = ftell(FH);
	fseek(FH, 0, SEEK_END);
	end = ftell(FH);
	fseek(FH, 0, SEEK_SET);
	long len = end-start;
	char* BUF = new char[len];
	if(fread((void*)BUF, 1, len, FH) != len){
		printf("LOAD LEN TOO SMALL\n");
		fclose(FH);
		delete [] BUF;
		return 0;
	}

	jclass ret;
	ret = env->DefineClass(Name, 0, (const jbyte*)BUF, len);
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
	}

	if(ret == 0){
		printf("COULD NOT LOAD CLASS\n");
		fclose(FH);
		delete [] BUF;
		return 0;
	}

	fclose(FH);
	delete [] BUF;

	return ret;
}


/////////////////////////////////////////////////////////////////////////////////////
jclass LoadClass(JNIEnv* env){

// To check signatures
//C:\Program Files\Java\jdk1.5.0_16\bin>javap -s -classpath "C:\Projects\java\JavaMinion\build\classes\minion" TestMinion

	jclass ret;
	if(ret = env->FindClass("minion/TestMinion")){
		return ret;
	}
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
	}

	//ret = LoadClass(env, "C:\\Projects\\java\\JavaMinion\\build\\classes\\minion\\TestMinion.class", "minion/TestMinion");
	//LoadClass(env, "C:\\Projects\\java\\JavaMinion\\build\\classes\\minion\\TestMinion$TestThread.class", "minion/TestMinion$TestThread");
	
	String str = AppDir + "TestMinion.class";

	printf("Dir is: %s\n", str.Str());

	ret = LoadClass(env, str.Str(), "minion/TestMinion");
	str = AppDir + "TestMinion$TestThread.class";
	LoadClass(env, str.Str(), "minion/TestMinion$TestThread");
	//ret = LoadClass(env, "TestMinion.class", "minion/TestMinion");
	//LoadClass(env, "TestMinion$TestThread.class", "minion/TestMinion$TestThread");

	return ret;
}

/////////////////////////////////////////////////////////////////////////////////////
jobject FindJavaWindow(JNIEnv* env, jobject par, String& Tag, String& Class){
	printf("LOOKING FOR: %s, %s\n", Tag.Str(), Class.Str());
	jclass comp_cls = env->FindClass("java/awt/Component");
	jclass cont_cls = env->FindClass("java/awt/Container");
	jclass window_cls = env->FindClass("java/awt/Window");
	jclass frame_cls = env->FindClass("java/awt/Frame");
	jclass class_cls = env->FindClass("java/lang/Class");

	Class.CheckEndQuotes(1, 1);
	int iNumeric = 0;
	if(!Tag.CheckEndQuotes(1,1)){
		
		Tag.Trim();
		CDataInt I;
		if(!I.DataFromString(Tag)){
			return 0;
		}
		iNumeric = I.Data;
		printf("NUMERIC WINDOW: %d (%s)\n", iNumeric, Class.Str());
	}

	jmethodID getClassName = env->GetMethodID(class_cls, "getName", "()Ljava/lang/String;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return 0;
	}

	jmethodID getFrames = env->GetStaticMethodID(frame_cls, "getFrames", "()[Ljava/awt/Frame;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return 0;
	}

	//jmethodID getOwnerlessWindows = env->GetStaticMethodID(window_cls, "getOwnerlessWindows", "()[Ljava/awt/Window;");
	//jmethodID getOwnerlessWindows = env->GetStaticMethodID(window_cls, "getWindows", "()[Ljava/awt/Window;");
	//if(env->ExceptionOccurred()){
	//	env->ExceptionDescribe();
	//	env->ExceptionClear();
	//	return 0;
	//}


	jclass minion_cls = LoadClass(env);
	if(!minion_cls){
		return 0;
	}
	jobject minion_obj = CreateObject(env, minion_cls);
	if(!minion_obj){
		return 0;
	}

	jmethodID getTopWin = env->GetMethodID(minion_cls, "getTopWindow", "(Ljava/lang/String;Ljava/lang/String;)Ljava/awt/Window;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return 0;
	}

	jstring jClass = env->NewStringUTF(Class.Str());
	jstring jTag = env->NewStringUTF(Tag.Str());
	jobject TopWin = env->CallObjectMethod(minion_obj, getTopWin, jTag, jClass);

	// GetTitle 
	//jmethodID getTitle = env->GetMethodID(frame_cls, "getTitle", "()Ljava/lang/String;");
	//if(env->ExceptionOccurred()){
	//	env->ExceptionDescribe();
	//	env->ExceptionClear();
	//	return 0;
	//}

	// Get top level frame ------------------------------------------
	jarray arr;
	if(par == 0){

		if(TopWin){
			return TopWin;
		}


		// Get Frames -----------
		arr = (jarray)env->CallStaticObjectMethod(frame_cls, getFrames);
		//arr = (jarray)env->CallStaticObjectMethod(window_cls, getOwnerlessWindows);
		if(env->ExceptionOccurred()){
			env->ExceptionDescribe();
			env->ExceptionClear();
			return 0;
		}
	// Get container components ------------------------------------------
	}else{
		jclass cls = env->GetObjectClass(par);
		jmethodID getComponents = env->GetMethodID(cls, "getComponents", "()[Ljava/awt/Component;");
		
		// This is just a check to see if getComponents exists for class
		// Should probably use 'env->IsInstanceOf'
		if(env->ExceptionOccurred()){
			env->ExceptionClear();
			return 0;
		}
		arr = (jarray)env->CallObjectMethod(par, getComponents);
	}

	// Cycle through objects to get matching tag/class ------------------------------------------
	jmethodID getTitle;
	String sTitle;
	jsize len = env->GetArrayLength(arr);
	printf("Frame Length is: %d\n", len);
	for(jsize ind = 0; ind < len; ind++){
		jobject frame = env->GetObjectArrayElement((jobjectArray)arr, ind);

		jclass cls = env->GetObjectClass(frame);

		getTitle = getTitleID(env, cls);  // Override getTitle
		if(getTitle){
			jstring temp = (jstring)env->CallObjectMethod(frame, getTitle);
			sTitle = GetString(env, temp);
		}else{
			// Has to be numeric if doesnt have getTitle
			//return 0;
			sTitle = "";  // Numeric not checked til later
		}
		
		jstring temp = (jstring)env->CallObjectMethod(cls, getClassName);
		String sClass = GetString(env, temp);
		printf("  Class: %s, Title: %s\n", sClass.Str(), sTitle.Str());

		// This needs to be partial, too...  really, just copy
		// what we have from DataWindow FindMe
		if(sClass == Class){

			// Check if searching for numeric
			if(iNumeric){
				int iN = GetNumeric(env, cls, frame, (jobjectArray)arr, len);
				printf("SEARCHING NUMERIC: %d, %d\n", iN, iNumeric);
				if(iN == iNumeric){
					printf("NUMERIC WINDOW FOUND: %d, %s\n", iNumeric, Class.Str());
					return frame;
				}
				//else{
				//	printf("NUMERIC WINDOW NOT FOUND: %d, %s\n", iNumeric, Class.Str());
				//	return 0;
				//}
			}

			printf("CLASS FOUND\n");
			String Star = "*";
			String Temp;
			if(Tag.FindOneOf(Star) >= 0){
				Tag.Parse(Star, Temp);
				Tag = Temp;
				printf("STARLESS TAG: %s\n", Tag.Str());
			}
			if(sTitle.Find(Tag) >= 0){
				printf("WINDOW FOUND: %s, %s\n", sTitle.Str(), sClass.Str());
				return frame;		
			}
		}			
	}
	return 0;
}

/////////////////////////////////////////////////////////////////////////////////////
SSI_INT64 FindMe(JNIEnv* env, String& Path, JavaWin& aWin){
	//Path.S  // Eventually set quote state
	JavaWin Ret;
	String ObjDelim = ";";
	String ElemDelim = ",";
	String Elem;
	String Tag;
	jobject win = 0;
	while(Path.Parse(ObjDelim, Elem) >= 0){
		printf("Elem: %s\n", Elem.Str());
		Elem.Parse(ElemDelim, Tag);
		printf("Tag:%s, Class:%s\n", Tag.Str(), Elem.Str());
		win = FindJavaWindow(env, win, Tag, Elem);
		if(win == 0){
			return 0;
		}
	}
	printf("Path: %s\n", Path.Str());
	Path.Parse(ElemDelim, Tag);
	Elem = Path;
	printf("Tag:%s, Class:%s\n", Tag.Str(), Elem.Str());
	win = FindJavaWindow(env, win, Tag, Elem);
	if(win == 0){
		return 0;
	}

	aWin.obj = win;
	aWin.Class = Elem;
	aWin.Tag = Tag;
	return 1;
}


/////////////////////////////////////////////////////////////////////////////////////
String ListMethods(JNIEnv* env, jobject in_obj, String& sDelim){

	jclass class_cls = env->FindClass("java/lang/Class");
	// Not used, yet
	jclass method_cls = env->FindClass("java/lang/reflect/Method");
	String Ret;

	jmethodID getMethods = env->GetMethodID(class_cls, "getMethods", "()[Ljava/lang/reflect/Method;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return Ret;
	}
	
	// Get Methods -----------
	jarray arr = (jarray)env->CallObjectMethod(in_obj, getMethods);
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return Ret;
	}

	jsize len = env->GetArrayLength(arr);
	//printf("Method Length is: %d\n", len);

	for(jsize ind = 0; ind < len; ind++){
		jobject method = env->GetObjectArrayElement((jobjectArray)arr, ind);
		String s = toString(env, method);
		Ret = Ret + s + sDelim;
		//printf("Method %d: %s\n", ind, s.Str());
	}
	return Ret;
}

String GetLoadMethods(JNIEnv* env, jobject in_obj){
	String Ret = ListMethods(env, in_obj, String("\n"));
	return Ret;
}

String JavaStringFromType(SSI_INT64 T){
	String Ret;
	if(T == CDataString::GetRegisteredType()){
		Ret = "Ljava/lang/String;";
	}else if(T == CDataInt::GetRegisteredType()){
		Ret = "I";
	}else if(T == CDataReal::GetRegisteredType()){
	}else if(T == CDataBool::GetRegisteredType()){
		Ret = "Z";
	}else if(T == CDataVoid::GetRegisteredType()){
		Ret = "V";
	}else{
	}
	return Ret;
}

/////////////////////////////////////////////////////////////////////////////////////
void EvaluateLoadFunction(JNIEnv* env, jobject in_obj, SSI_FunctionAPI& theAPI){
	printf("0000 Custom Function Detected: %s\n", theAPI.m_FunctionName.Str());

	String FuncString;
	FuncString = "(";
	for(int i = 0; i < theAPI.GetNumParams(); i++){
		FuncString = FuncString + JavaStringFromType(theAPI.GetParameterType(i));
	}
	FuncString = FuncString + ")";
	FuncString = FuncString + JavaStringFromType(theAPI.GetReturnData()->GetType()); 
	printf("FuncString: %s\n", FuncString.Str());

	jclass cls = env->GetObjectClass(in_obj);
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jmethodID custom = env->GetMethodID(cls, theAPI.m_FunctionName.Str(), FuncString.Str());
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	// Get Data Classes and Constructors ------------------------------------
	jclass int_cls = env->FindClass("java/lang/Integer");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jmethodID int_create = env->GetStaticMethodID(int_cls, "valueOf", "(I)Ljava/lang/Integer;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jmethodID int_value = env->GetMethodID(int_cls, "intValue", "()I");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}


	jclass bool_cls = env->FindClass("java/lang/Boolean");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jmethodID bool_create = env->GetStaticMethodID(bool_cls, "valueOf", "(Z)Ljava/lang/Boolean;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jmethodID bool_value = env->GetMethodID(bool_cls, "booleanValue", "()Z");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}


	jclass double_cls = env->FindClass("java/lang/Double");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jmethodID double_create = env->GetStaticMethodID(double_cls, "valueOf", "(D)Ljava/lang/Double;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jmethodID double_value = env->GetMethodID(double_cls, "doubleValue", "()D");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	// Create Parameter Array ------------------------------------
	jclass obj_cls = env->FindClass("java/lang/Object");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jobjectArray arr = env->NewObjectArray(theAPI.GetNumParams(), obj_cls, 0);
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	SSI_INT64 T;
	jobject new_obj = 0;

	for(int i = 0; i < theAPI.GetNumParams(); i++){
		T = theAPI.GetParameterType(i);
		if(T == CDataString::GetRegisteredType()){
			String S = SSI_EXTRACT(CDataString, i);
			jstring j = env->NewStringUTF(S.Str());
			new_obj = (jobject)j;
			printf("ADDING STRING\n");
		}else if(T == CDataInt::GetRegisteredType()){
			printf("ADDING INT\n");
			jint ji = SSI_EXTRACT(CDataInt, i);
			new_obj = env->CallStaticObjectMethod(int_cls, int_create, ji);
			if(env->ExceptionOccurred()){
				env->ExceptionDescribe();
				env->ExceptionClear();
				return;
			}

		}else if(T == CDataReal::GetRegisteredType()){
			printf("ADDING REAL\n");
			jdouble jd = (jfloat)SSI_EXTRACT(CDataReal, i);
			new_obj = env->CallStaticObjectMethod(double_cls, double_create, jd);
			if(env->ExceptionOccurred()){
				env->ExceptionDescribe();
				env->ExceptionClear();
				return;
			}

		}else if(T == CDataBool::GetRegisteredType()){
			printf("ADDING BOOL\n");
			jboolean jb = SSI_EXTRACT(CDataBool, i);
			new_obj = env->CallStaticObjectMethod(bool_cls, bool_create, jb);
			if(env->ExceptionOccurred()){
				env->ExceptionDescribe();
				env->ExceptionClear();
				return;
			}
		}else if(T == CDataVoid::GetRegisteredType()){
			printf("ADDING VOID\n");
		}else{
			printf("ADDING ELSE\n");
		}

		if(new_obj){
			env->SetObjectArrayElement(arr, i, new_obj);
			if(env->ExceptionOccurred()){
				env->ExceptionDescribe();
				env->ExceptionClear();
				return;
			}
		}
		new_obj = 0;
	}


  // Initialize Java Minion ------------------------------------
	jclass minion_cls = LoadClass(env);
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jobject minion = CreateObject(env, minion_cls);

	jmethodID PrepareMethod = env->GetMethodID(minion_cls, "PrepareMethod", "(Ljava/awt/Component;Ljava/lang/reflect/Method;)V");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jmethodID InvokeMethod = env->GetMethodID(minion_cls, "InvokeMethod", "([Ljava/lang/Object;)Ljava/lang/Object;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

//	jmethodID GetStatus = env->GetMethodID(minion_cls, "GetStatus", "()I");
//	if(env->ExceptionOccurred()){
//		env->ExceptionDescribe();
//		env->ExceptionClear();
//		return;
//	}


	printf("METHODS FOUND OK\n");

	//env->CallObjectMethodV(minion, InvokeMethod
	//env->CallVoidMethod(minion, requestFocus, in_obj);

	jobject meth = env->ToReflectedMethod(cls, custom, 0);
	env->CallVoidMethod(minion, PrepareMethod, in_obj, meth);
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	//jobject field = env->GetObjectArrayElement((jobjectArray)arr, ind);
	//env->SetObjectArrayElement(arr, ind, jobj);


	T = theAPI.GetReturnData()->GetType();
  jobject res = env->CallObjectMethod(minion, InvokeMethod, arr);

	if(T == CDataString::GetRegisteredType()){
		CDataString S;
		S.Data = GetString(env, (jstring)res);
		theAPI.SetReturnData(&S);
		//env->CallObjectMethodV(in_obj, custom, args);
	}else if(T == CDataInt::GetRegisteredType()){
		if(!env->IsInstanceOf(res, int_cls)){
			return;
		}
		CDataInt I;
		I.Data = env->CallBooleanMethod(res, int_value);
		theAPI.SetReturnData(&I);
		return;
	}else if(T == CDataReal::GetRegisteredType()){
		if(!env->IsInstanceOf(res, double_cls)){
			return;
		}
		CDataReal R;
		R.Data = env->CallDoubleMethod(res, double_value);
		theAPI.SetReturnData(&R);
		return;
	}else if(T == CDataBool::GetRegisteredType()){
		if(!env->IsInstanceOf(res, bool_cls)){
			return;
		}
		CDataBool B;
		B.Data = env->CallBooleanMethod(res, bool_value);
		theAPI.SetReturnData(&B);
		return;
	}else if(T == CDataVoid::GetRegisteredType()){
		//env->CallVoidMethodV(in_obj, custom, args);
		// Must recieve return object
		//env->CallVoidMethodV(minion, InvokeMethod, args);
		//env->CallVoidMethod(minion, InvokeMethod, arr);
		//env->CallVoidMethodVminion, InvokeMethod, iARGS);
	}else{
	}

	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	//while(env->CallIntMethod(minion, GetStatus) == 0){
	//	Sleep(10000);
	//}


	//delete [] args;

	/*
	jclass cls = env->GetObjectClass(in_obj);
	jmethodID custom = env->GetMethodID(minion_cls, "requestFocus", "(Ljava/awt/Component;)V");	

	jclass comp_cls = env->FindClass("java/awt/Component");
	if(env->IsInstanceOf(in_obj, comp_cls)){
		jclass minion_cls = LoadClass(env);
		jobject minion = CreateObject(env, minion_cls);
		jmethodID requestFocus = env->GetMethodID(minion_cls, "requestFocus", "(Ljava/awt/Component;)V");
		if(env->ExceptionOccurred()){
			env->ExceptionDescribe();
			env->ExceptionClear();
			return;
		}
		env->CallVoidMethod(minion, requestFocus, in_obj);
		if(env->ExceptionOccurred()){
			env->ExceptionDescribe();
			env->ExceptionClear();
			return;
		}
	}
	*/
}



/////////////////////////////////////////////////////////////////////////////////////
String ListFields(JNIEnv* env, jobject in_obj, String& sDelim){
	jclass class_cls = env->FindClass("java/lang/Class");
	// Not used, yet
	jclass method_cls = env->FindClass("java/lang/reflect/Field");
	String Ret;

	jmethodID getFields = env->GetMethodID(class_cls, "getFields", "()[Ljava/lang/reflect/Field;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return Ret;
	}
	
	// Get Methods -----------
	jarray arr = (jarray)env->CallObjectMethod(in_obj, getFields);
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return Ret;
	}

	jsize len = env->GetArrayLength(arr);
	//printf("Field Length is: %d\n", len);

	for(jsize ind = 0; ind < len; ind++){
		jobject field = env->GetObjectArrayElement((jobjectArray)arr, ind);
		String s = toString(env, field);
		Ret = Ret + s + sDelim;
		//printf("Field %d: %s\n", ind, s.Str());
	}
	return Ret;
}

/////////////////////////////////////////////////////////////////////////////////////
void RequestFocus(JNIEnv* env, jobject in_obj){
	
	jclass comp_cls = env->FindClass("java/awt/Component");
	if(env->IsInstanceOf(in_obj, comp_cls)){
		jclass minion_cls = LoadClass(env);
		jobject minion = CreateObject(env, minion_cls);
		jmethodID requestFocus = env->GetMethodID(minion_cls, "requestFocus", "(Ljava/awt/Component;)V");
		if(env->ExceptionOccurred()){
			env->ExceptionDescribe();
			env->ExceptionClear();
			return;
		}
		env->CallVoidMethod(minion, requestFocus, in_obj);
		if(env->ExceptionOccurred()){
			env->ExceptionDescribe();
			env->ExceptionClear();
			return;
		}
	}
}

/////////////////////////////////////////////////////////////////////////////////////
jboolean IsVisible(JNIEnv* env, jobject in_obj){
	
	jclass comp_cls = env->FindClass("java/awt/Component");
	if(env->IsInstanceOf(in_obj, comp_cls)){
		jclass minion_cls = LoadClass(env);
		jobject minion = CreateObject(env, minion_cls);
		jmethodID requestFocus = env->GetMethodID(minion_cls, "isVisible", "(Ljava/awt/Component;)Z");
		if(env->ExceptionOccurred()){
			env->ExceptionDescribe();
			env->ExceptionClear();
			return 0;
		}
		
		jboolean b = env->CallBooleanMethod(minion, requestFocus, in_obj);
		if(env->ExceptionOccurred()){
			env->ExceptionDescribe();
			env->ExceptionClear();
			return 0;
		}

		return b;
	}
	return 0;
}


/////////////////////////////////////////////////////////////////////////////////////
String DispWindow(JNIEnv* env, jobject in_obj, String& Pre, String& Delim){
	String Ret;
	String Temp;
	jclass cls = env->GetObjectClass(in_obj);
	jmethodID getTitle = 0;

	jclass class_cls = env->FindClass("java/lang/Class");
	jclass cont_cls = env->FindClass("java/awt/Container");
	jmethodID getClassName = env->GetMethodID(class_cls, "getName", "()Ljava/lang/String;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return Ret;
	}

	if(env->IsInstanceOf(in_obj, cont_cls)){
	}else{
		return Ret;
	}
	jmethodID getComponents = env->GetMethodID(cls, "getComponents", "()[Ljava/awt/Component;");		
	jarray arr = (jarray)env->CallObjectMethod(in_obj, getComponents);

	// Cycle through objects to get matching tag/class ------------------------------------------
	jsize len = env->GetArrayLength(arr);
	printf("%sChildren: %d\n", Pre.Str(), len);
	for(jsize ind = 0; ind < len; ind++){
		jobject frame = env->GetObjectArrayElement((jobjectArray)arr, ind);
		String sTitle;

		jclass cls = env->GetObjectClass(frame);
		getTitle = getTitleID(env, cls);  // Override getTitle

		if(getTitle){
			jstring temp = (jstring)env->CallObjectMethod(frame, getTitle);
			sTitle = GetString(env, temp);
		}else{
			sTitle.Format("0", 0);
		}
		
		jstring temp = (jstring)env->CallObjectMethod(cls, getClassName);
		String sClass = GetString(env, temp);
		printf("%sChild %d = Class: %s, Title: %s\n", Pre.Str(), ind, sClass.Str(), sTitle.Str());
		Temp.Format("%s{Class: %s} {Tag: %s}%s", Pre.Str(), sClass.Str(), sTitle.Str(), Delim.Str());
		Ret = Ret + Temp;
		Ret = Ret + DispWindow(env, frame, Pre + ".", Delim);
	}
	return Ret;
}

/////////////////////////////////////////////////////////////////////////////////////
jobject GetTopLevel(JNIEnv* env, jobject in_obj){
	jclass comp_cls = env->FindClass("java/awt/Component");
	jclass window_cls = env->FindClass("java/awt/Window");
	jmethodID getParent = env->GetMethodID(comp_cls, "getParent", "()Ljava/awt/Container;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return 0;
	}

	if(env->IsInstanceOf(in_obj, window_cls)){
		return in_obj;
	}

	if(env->IsInstanceOf(in_obj, comp_cls)){
		jobject par = in_obj;
		jobject temp = 0;
		while(temp = env->CallObjectMethod(par, getParent)){
			par = temp;
		}
		return par;
	}
	return 0;
}

// No references here
String GetName(String Tag, String Class, int iTag){
	String Toks = "&.;:,=-~'^#\"\'()/\\*$@!%><[]{}+?";
	SSI_INT64 i;
	Tag.Trim();
	if(Tag == ""){
		Class.Reverse();
		i = Class.ReverseFind(".");
		if(i > 0){
			String Temp;
			Class.Parse(".", Temp);
			Temp.Reverse();
			Tag.Format("%d", iTag);
			Tag = Temp + Tag;
		}
	}

	String s;
	Tag.Trim();
	if(Tag.Find(" ") >= 0){
		Tag.Parse(" ", s);  // Only get from first space
		Tag = s;
	}

	int iLen = Toks.GetLength();	
	for(i = 0; i < iLen; i++){
		s.Format("%c", Toks[i]);
		Tag.Replace(s.Str(), "_");
	}

	return Tag;
}

/////////////////////////////////////////////////////////////////////////////////////
SSI_INT64 SaveDecls(JNIEnv* env, jobject in_obj, int iNumeric, File& aFile, int iLevel){
	String Temp;
	jclass cls = env->GetObjectClass(in_obj);
	jmethodID getTitle = 0;

	jclass class_cls = env->FindClass("java/lang/Class");
	jclass cont_cls = env->FindClass("java/awt/Container");
	jmethodID getClassName = env->GetMethodID(class_cls, "getName", "()Ljava/lang/String;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return 0;
	}

	if(env->IsInstanceOf(in_obj, cont_cls)){
	}else{
		return 0;
	}
	jmethodID getComponents = env->GetMethodID(cls, "getComponents", "()[Ljava/awt/Component;");		
	jarray arr = (jarray)env->CallObjectMethod(in_obj, getComponents);
	jsize len = env->GetArrayLength(arr);

	String Tag;
	String Class;
	int isNumeric = 0;
	getTitle = getTitleID(env, cls);  // Override getTitle	
	if(getTitle){
		jstring temp = (jstring)env->CallObjectMethod(in_obj, getTitle);
		Tag = GetString(env, temp);
	}else{
		Tag = "";
		isNumeric = 1;
	}

	// If text field has multi-lines
	if(Tag.FindOneOf("\n\r") >= 0){
		Tag = "";
		isNumeric = 1;
	}

	Tag.Trim();
	if(Tag.GetLength() == 0){
		isNumeric = 1;
	}

	jstring temp = (jstring)env->CallObjectMethod(cls, getClassName);
	Class = GetString(env, temp);

	String Prefix;
	int i = iLevel;
	while(i > 0){
		Prefix = Prefix + "\t";
		i = i - 1;
	}

	String Name = GetName(Tag, Class, iNumeric);
	String sLine;
	sLine.Format("%s[ ]JavaWin \"%s\"\n", Prefix.Str(), Name.Str()/*GetName(Tag, Class, Index)*/);
	aFile.WriteLine(sLine);
	if(isNumeric){
		sLine.Format("%s\t( )Tag=%d\n", Prefix.Str(), iNumeric);  // Check Numeric
	}else{
		sLine.Format("%s\t( )Tag=\"%s\"\n", Prefix.Str(), Tag.Str());  // Check Numeric
	}
	aFile.WriteLine(sLine);
	sLine.Format("%s\t( )Class=\"%s\"\n", Prefix.Str(), Class.Str());
	aFile.WriteLine(sLine);
	if(len > 0){
		sLine.Format("%s\t( )Parent=1\n", Prefix.Str());		
	}else{
		sLine.Format("%s\t( )Parent=0\n", Prefix.Str());
	}
	aFile.WriteLine(sLine);
	if(iLevel > 0){
		sLine.Format("%s\t( )Child=1\n", Prefix.Str());		
	}else{
		sLine.Format("%s\t( )Child=0\n", Prefix.Str());
	}
	aFile.WriteLine(sLine);

	// Cycle through objects to get matching tag/class ------------------------------------------
	for(jsize ind = 0; ind < len; ind++){
		
		jobject frame = env->GetObjectArrayElement((jobjectArray)arr, ind);
		jclass frame_cls = env->GetObjectClass(frame);
		iNumeric = GetNumeric(env, frame_cls, frame, (jobjectArray)arr, len);
		if(!SaveDecls(env, frame, iNumeric, aFile, iLevel+1)){
			return 0;
		}
	}
	return 1;
}

/////////////////////////////////////////////////////////////////////////////////////
SSI_INT64 Click(JNIEnv* env, jobject obj){
	jclass minion_cls = LoadClass(env);
	if(!minion_cls){
		return 0;
	}
	jobject minion_obj = CreateObject(env, minion_cls);
	if(!minion_obj){
		return 0;
	}

	jmethodID click = env->GetMethodID(minion_cls, "MouseClick", "(Ljava/awt/Component;)V");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return 0;
	}

	env->CallVoidMethod(minion_obj, click, obj);
	return 0;
}


/////////////////////////////////////////////////////////////////////////////////////
void FindFrame(JNIEnv* env, String& Tag, String& Class){
	// Can pass in a tag and compare against title
	
	jclass frame_cls = env->FindClass("java/awt/Frame");
	jmethodID getFrames = env->GetStaticMethodID(frame_cls, "getFrames", "()[Ljava/awt/Frame;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}

	jmethodID getTitle = env->GetMethodID(frame_cls, "getTitle", "()Ljava/lang/String;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}
	
	//jmethodID getOwner = env->GetMethodID(frame_cls, "getOwner", "()Ljava/awt/Window;");
	//if(env->ExceptionOccurred()){
	//	env->ExceptionDescribe();
	//	env->ExceptionClear();
	//	return;
	//}

	// Get Frames -----------
	jarray arr = (jarray)env->CallStaticObjectMethod(frame_cls, getFrames);
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
		env->ExceptionClear();
		return;
	}


	jsize len = env->GetArrayLength(arr);
	printf("Frame Length is: %d\n", len);

	for(jsize ind = 0; ind < len; ind++){
		jobject frame = env->GetObjectArrayElement((jobjectArray)arr, ind);
		String s = toString(env, frame);
		printf("Frame %d: %s\n", ind, s.Str());

		jclass cls = env->GetObjectClass(frame);
		jstring title = (jstring)env->CallObjectMethod(frame, getTitle);
		String sTitle = GetString(env, title);
		String sClass = toString(env, cls);
		printf("  Class: %s, Title: %s\n", sClass.Str(), sTitle.Str());
	}
}

//Signature Java Programming Language Type 
//Z boolean  
//B byte 
//C char 
//S short 
//I int 
//J long 
//F float 
//D double 
//L fully-qualified-class;  fully-qualified-class  
//[ type type[] 
//( arg-types ) ret-type method type 

void CleanupThread(JavaVM* VM, int Code){
	if(VM){
	 VM->DetachCurrentThread();
	}
	ExitThread(Code);
}

/////////////////////////////////////////////////////////////////////////////////////
DWORD WINAPI ThreadFunc( LPVOID lpParam ) { 
	// I only do it this way so I can do SSI_EXTRACT
	JavaAPI* API = (JavaAPI*)lpParam;
	String ExtraData = *(API->ExtraData);

	SSI_FunctionAPI& theAPI = *(API->theAPI);
	if(&theAPI == 0){
		ExitThread(-1);
		return 0;
	}

	JavaVM*	javaVM = GetVM();
	if(javaVM == 0){
		J_MAKEERR0(ERR_J01200);
		CleanupThread(javaVM, -1);
		return 1;
	}

	// The thread is attached in this call...
	JNIEnv*	env = GetEnv(javaVM);
	if(env == 0){
		J_MAKEERR0(ERR_J01201);
		CleanupThread(javaVM, -1);
		return 1;
	}

	LoadClass(env);

	if(theAPI.m_FunctionName == "Exists"){		
		CDataBool B;
		JavaWin aWin;
		B.Data = FindMe(env, ExtraData, aWin);
		theAPI.SetReturnData(&B);
		CleanupThread(javaVM, 0);
		return 1;
	}

	ExtraData.Parse(";", AppDir);

	JavaWin aWin;
	int ctr = 0;
	while(!FindMe(env, ExtraData, aWin)){
		ctr++;
		if(ctr > 50){
			printf("COULD NOT FIND WINDOW: %s\n", ExtraData.Str());
			J_MAKEERR1(ERR_J01100, ExtraData.Str());
  		CleanupThread(javaVM, -1);
			return 1;
		}
		Sleep(100);
	}

	if(theAPI.m_FunctionName == "ListMethods"){
		// Well, already we dont have a class name
		jclass main_cls = 0;
		String sDelim = SSI_EXTRACT(CDataString, 0);
		main_cls = env->GetObjectClass(aWin.obj); //env->FindClass("ptd/Main");
		CDataString sRet;
		sRet.Data = ListMethods(env, main_cls, sDelim);
		theAPI.SetReturnData(&sRet);
		CleanupThread(javaVM, 1);
		return 1;
	}else if(theAPI.m_FunctionName == "LoadMethods"){
		// Well, already we dont have a class name
		jclass main_cls = 0;
		main_cls = env->GetObjectClass(aWin.obj); //env->FindClass("ptd/Main");
		CDataString sRet;
		sRet.Data = GetLoadMethods(env, main_cls);
		// Override return type
		theAPI.GetReturnData()->SetType(CDataString::GetRegisteredType());
		theAPI.SetReturnData(&sRet);
		printf("METHODS: %s\n", sRet.Data.Str());
		CleanupThread(javaVM, 1);
		return 1;
	}else if(theAPI.m_FunctionName == "ListFields"){
		jclass main_cls = 0;
		String sDelim = SSI_EXTRACT(CDataString, 0);
		main_cls = env->GetObjectClass(aWin.obj); //main_cls = env->FindClass("ptd/Main");
		CDataString sRet;
		sRet.Data = ListFields(env, main_cls, sDelim);
		theAPI.SetReturnData(&sRet);
		CleanupThread(javaVM, 1);
		return 1;
  }else if(theAPI.m_FunctionName == "DispWindow"){
		String sDelim = SSI_EXTRACT(CDataString, 0);
		CDataString sRet;
		sRet.Data = DispWindow(env, aWin.obj, String(""), sDelim);
		theAPI.SetReturnData(&sRet);
		CleanupThread(javaVM, 1);
		return 1;
	}else if(theAPI.m_FunctionName == "FindFrame"){
		String sTag = SSI_EXTRACT(CDataString, 0);
		String sClass = SSI_EXTRACT(CDataString, 1);
		FindFrame(env, sTag, sClass);
		CleanupThread(javaVM, 1);
		return 1;
	}else if(theAPI.m_FunctionName == "GetText"){
		jclass cls = env->GetObjectClass(aWin.obj);
		jmethodID txtid = getTitleID(env, cls);
		CDataString Ret;
		if(txtid){
			jstring txt = (jstring)env->CallObjectMethod(aWin.obj, txtid);
			Ret.Data = GetString(env, txt);
		}else{
			// Create an error
		}
		theAPI.SetReturnData(&Ret);
		CleanupThread(javaVM, 1);
		return 1;
	}else if(theAPI.m_FunctionName == "SetText"){
		jclass cls = env->GetObjectClass(aWin.obj);
		jmethodID txtid = setTitleID(env, cls);
		String sText = SSI_EXTRACT(CDataString, 0);
		if(txtid){
			jstring j = env->NewStringUTF(sText.Str());
			env->CallObjectMethod(aWin.obj, txtid, j);
		}else{
			// Create an error
		}
		CleanupThread(javaVM, 1);
		return 1;
	}else if(theAPI.m_FunctionName == "SaveDecls"){
		jclass cls = env->GetObjectClass(aWin.obj);
		String sFile = SSI_EXTRACT(CDataString, 0);

		jobject top = GetTopLevel(env, aWin.obj);
		if(!top){
			J_MAKEERR2(ERR_J01220, aWin.Tag.Str(), aWin.Class.Str());
			CleanupThread(javaVM, 1);
			return 1;
		}
    // Must use pointer, else file will not close properly
		File* aFile = new File();

    String LocFile = sFile;
    // Environment doesnt exist, I think...
//    theAPI.m_ReturnStatus = theAPI.m_Engine->Environment->GetAbsolutePath(sFile, LocFile);
//    if(!theAPI.m_ReturnStatus){
//      CleanupThread(javaVM, 1);
//      return 1;
//    }

		CStatus aStat = aFile->Open(LocFile, "w");  // Closes on destroy
		if(!aStat){
			theAPI.m_ReturnStatus = aStat;
			CleanupThread(javaVM, 1);
      delete aFile;
			return 1;
		}
		SSI_INT64 iRet = SaveDecls(env, top, 1, *aFile, 0);
		CDataBool b;
		b.Data = iRet;
		theAPI.SetReturnData(&b);
    delete aFile;
		CleanupThread(javaVM, 1);

		return 1;
	}else if(theAPI.m_FunctionName == "Click"){
		Click(env, aWin.obj);
		return 1;
	}else if(theAPI.m_FunctionName == "TypeKeys"){
		RequestFocus(env, aWin.obj);
		CleanupThread(javaVM, 1);
		return 1;
	}else if(theAPI.m_FunctionName == "SetFocus"){
		RequestFocus(env, aWin.obj);
		CleanupThread(javaVM, 1);
		return 1;
	}else if(theAPI.m_FunctionName == "IsVisible"){
		CDataBool B;
		B.Data = IsVisible(env, aWin.obj);
		theAPI.SetReturnData(&B);
		CleanupThread(javaVM, 1);
		return 1;
	}else{
    // Do an application defined function
		EvaluateLoadFunction(env, aWin.obj, theAPI);
		CleanupThread(javaVM, 1);
		
		return 1;
	}


	CleanupThread(javaVM, 1);
	return 0;
	/* Attach to existing JVM */
	
	/*
	if (javaVM->GetEnv((void **) &env, JNI_VERSION_1_2) == JNI_OK) {
		s.Data = s.Data + "JVM Detected\n";
		printf("Environment Retrieved\n", size);
	}else{
		printf("No Environtment\n", size);
		return 1;
	}

	if(env->ExceptionOccurred()){
		s.Data = s.Data + "Exception Occurred 1\n";
		env->ExceptionClear();
	}
	*/
	
	


//	printf("wha?\n");
//	if(env->ExceptionOccurred()){
//		s.Data = s.Data + "Exception Occurred 3\n";
//		env->ExceptionClear();
//	}

//	jint zz = env->GetVersion();
//	s.Data = s.Data + "Version: \n";
//	String szz;
//	szz.Format("%d", zz);
//	s.Data = s.Data + szz + "\n";

/*
	jclass main_cls = 0;
	main_cls = env->FindClass("ptd/Main");

	if (main_cls == 0) {
		s.Data = s.Data + "Could not find class...\n";
	}else{
		s.Data = s.Data + "Class found successfully.\n";
	}

	jmethodID getMainFrameID = env->GetStaticMethodID(main_cls, "getMainFrame", "()Lptd/PTDMain;");
	if(getMainFrameID == 0){
		printf("Couldnt find method...\n");
	}
	jobject main_obj = env->CallStaticObjectMethod(main_cls, getMainFrameID);
	if(main_obj == 0){
		printf("Could not get PTD\n");
	}
	
	jclass ptd_cls = 0;
	ptd_cls = env->FindClass("ptd/PTDMain");


	// USEFUL FUNCTIONS ---------------------------------------------------
	jclass class_cls = env->FindClass("java/lang/Class");
	jclass method_cls = env->FindClass("java/lang/reflect/Method");
	// To be called on a class, *not* an object
	jmethodID toString = env->GetMethodID(class_cls, "toString", "()Ljava/lang/String;");
	jmethodID getName = env->GetMethodID(class_cls, "getName", "()Ljava/lang/String;");
	jmethodID getSimpleName = env->GetMethodID(class_cls, "getSimpleName", "()Ljava/lang/String;");
	jmethodID getSuperclass = env->GetMethodID(class_cls, "getSuperclass", "()Ljava/lang/Class;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
	}
	jmethodID getMethods = env->GetMethodID(class_cls, "getMethods", "()[Ljava/lang/reflect/Method;");
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
	}





	// Get Method -----------
	jarray arr = (jarray)env->CallObjectMethod(ptd_cls, getMethods);
	if(env->ExceptionOccurred()){
		env->ExceptionDescribe();
	}

	jsize len = env->GetArrayLength(arr);
	printf("Method Length is: %d\n", len);

	for(jsize ind = 0; ind < 200; ind++){
		jobject method = env->GetObjectArrayElement((jobjectArray)arr, ind);

		jstring js = (jstring)env->CallObjectMethod(method, toString);
	    const char *str = env->GetStringUTFChars(js, 0);
		printf("Method %d: %s\n", ind, str);
		env->ReleaseStringUTFChars(js, str);

	}

	// ----------------------

	jclass super_cls = (jclass)env->CallObjectMethod(ptd_cls, getSuperclass);
	jstring js = (jstring)env->CallObjectMethod(super_cls, toString);

    const char *str = env->GetStringUTFChars(js, 0);
	printf("Name: %s\n", str);
    env->ReleaseStringUTFChars(js, str);

	jmethodID openPSC = env->GetMethodID(ptd_cls, "closeAllScripts", "()Z");
	env->CallBooleanMethod(main_obj, openPSC);	
	
	javaVM->DetachCurrentThread();
	s.Data = s.Data + "Detached\n";
	theAPI->m_ReturnStatus = theAPI->SetReturnData(&s);
	ExitThread(1);
    return 0; 
*/
} 

/////////////////////////////////////////////////////////////////////////////////////
int CPhantomJVM::FunctionProcessor(SSI_FunctionAPI& theAPI)
{
	JavaAPI API;

	API.theAPI = &theAPI;
	API.ExtraData = &ExtraData;

  DWORD thread_id;
	HANDLE H = CreateThread(NULL, NULL, ThreadFunc, (LPVOID)&API, NULL, &thread_id);



	int bGo = 1;
	DWORD code = 0;
	while(bGo){
		GetExitCodeThread(H, &code);
		if(code == -1 || code == 1){
			bGo = 0;
		}
	}

	CloseHandle(H);

	// OK, so it seems the hang occurs because the message procedure
	// is waiting for this to finish... the message loop blocks!  Why?  There is
	// a separate thread created to handle the messages!

	// OH!  OK, so here is what is happening... The GetMsgProc gets a command, then
	// hangs the message loop while the command is being processed.  In the mean
	// time, the command causes the Java window to redraw, thereby causing a new
	// message to be created by the application.  This message wont be processed
	// until the GetMsgProc is finished with the current message (the original command).
	// However, the command wont finish because it is waiting for the application
	// to return, which wont return until the message is processed successfully.  So
	// we have two processes waiting for eachother to finish, even though they are
	// in different threads (they can be in a million threads, it wont matter... the
	// redraw thread and the message processing thread are still waiting for eachother
	// to finish).  So, why are we waiting for the message processing thread (the
	// Java Minion thread) to finish at all? (Thereby causing the lockup of GetMsgProc
	// in the first place)  We *have* to wait or else the return data type might not 
	// be successfully set.  So if we have to wait, but a hang will occur if we wait,
	// then what do we do?  Perhaps send a second WM_COMMAND to retrieve the result
	// data?

	return 1;
}

/////////////////////////////////////////////////////////////////////////////////////
//CPhantomWindow* CPhantomJVM::MakeWindow(void)
//{
//	return new CPhantomJVM();
//}

void CPhantomJVM::SetExtraData(String& In){
	ExtraData = In;
}
